home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr24 / sdf21.zip / SDF.ASM < prev    next >
Assembly Source File  |  1993-05-20  |  25KB  |  1,023 lines

  1. Title 'SDF : Speedy Disk Formatter'
  2.  
  3. ; **************************************************************************
  4. ; * THIS PROGRAM IS PUBLIC DOMAIN. You Are Free To Use It And Redistribute *
  5. ; * It, As Long As No Profit Is Made Out Of It. Redistribution Costs May   *
  6. ; * Not Exceed $5. This Notice May Not Be Removed Or Altered In Any Way.   *
  7. ; * Use At Your Own Risk. Author Will Not Be Held Responsible For Any Dama-*
  8. ; * ge That Might Result Of Use Or Misuse. Enjoy.               *
  9. ; **************************************************************************
  10.  
  11. ; This program is inspired from QDR by Vernon D. Buerg, which unfortunately
  12. ; has a bug in handling 3.5" floppies.
  13.  
  14. ; Better late than never, I dedicate this program to Ward Christensen, who
  15. ; showed us the way in the good old CP/M days ...
  16.  
  17. ; Jacques Pierson, Belgrade (Belgium), November 1987.
  18. ; CIS 76446,1516
  19.  
  20. ; Modification history:
  21. ; September 1990:  fixed bug with DMA boundary errors, and added code to turn
  22. ;    off the drive motor quickly.
  23. ; October 1990:  fixed bug in above bug fix.
  24.  
  25. M24    =    0    ;set to one at work, for an Olivetti M24 (ATT 6300) 
  26.  
  27. bell    equ    7
  28. bs    equ    8
  29. lf    equ    0Ah
  30. cr    equ    0Dh
  31. escape    equ    1Bh
  32. ulc    equ    0C9h    ;graphic char - Upper Left Corner
  33. llc    equ    0C8h    ;Lower Left Corner
  34. urc    equ    0BBh    ;Upper Right Corner
  35. lrc    equ    0BCh    ;Lower Right Corner
  36. vb    equ    0BAh    ;Vertical Border
  37. hb    equ    0CDh    ;Horizontal Border
  38. ;
  39. hsr    equ    0EFh    ;Head Step Rate : 4 ms
  40. hst    equ    0    ;Head Settle Time : 0 ms
  41. ;
  42.  
  43.  
  44. SDF    segment
  45.     assume ds:SDF, ss:SDF ,cs:SDF ,es:SDF
  46.  
  47.     org    0100h        ;make this a COM file
  48.  
  49.  
  50. start:    jmp    GetCmdLine
  51.  
  52. ; First describe our Disk Base Parms. We will make INT 1Eh to point here
  53. ; while formatting. Put at head of program so people without an assembler
  54. ; can easily patch this area w/ DEBUG.
  55.  
  56. OurDBP    equ    $
  57.  
  58.     db    hsr        ;high nibble : heads step rate
  59.                 ;low nibble, head unload time
  60.     db    2        ;DMA mode
  61.     db    255        ;clock ticks before stopping drive motor
  62.     db    2        ;sector size - 2 => 512 bytes
  63.     db    9        ;How many sectors per track
  64.     db    42        ;Gap length between sectors for R/W ops
  65.     db    -1        ;data length - Not used
  66.     db    80        ;Gap length when formatting
  67.     db    0F6h        ;Formatting char. Dos likes F6's
  68.     db    hst         ;Head settle time in ms.
  69.     db    1        ;Motor speed up time in 1/4 sec.
  70.  
  71. Welcome    db    cr,lf,'Speedy Disk Formatter, V1.0, '
  72.     db    '(c) Jacques Pierson, Nov 1987$'
  73.  
  74. UsageMessage    equ    $
  75.     db    cr,lf,lf,'Usage:  SDF drv: [switches]',cr,lf
  76.     db    'drv: mandatory and is either A: or B:,',cr,lf
  77.     db    'No switch => format standard 360K diskette, no verify',cr,lf
  78.     db    '/Q        => format Quad density (3',0abh,'" 720K disk)',cr,lf
  79.     db    '/V        => force Verify after format',cr,lf
  80.     db    'Multiple switches may be combined, e.g. SDF b:/q/v.'
  81.     db    cr,lf,lf,'$'
  82.  
  83. DriveMissing    db    cr,lf,lf,'Invalid or missing Drive Spec !$'
  84.  
  85. WrongSwitch    db    cr,lf,lf,'Unknown /switch in command line !$'
  86.  
  87. InsertDisk    db    cr,lf,lf,'Insert diskette in drive '
  88. Drive        db    'A, and press ENTER when ready ...$'
  89.  
  90. Again        db    cr,lf,lf,'Format complete,'
  91. Clusters    db    '      K available to user.'
  92.         db    cr,lf,'Press ENTER to format another diskette, '
  93.         db    'or ESCape to quit...$'
  94.  
  95. Formatting    db    cr,lf,lf,'Formatting '
  96. DiskType    db    'DSDD, Without$'
  97. Verify        db    ' Verify.',cr,lf,'$'
  98.  
  99. Track        db    cr,'Track: '
  100. TrackNr        db    '   Side: '
  101. SideNr        db    '   $'
  102.  
  103. ShowRetry    db    bs,'R$'
  104.  
  105. WritingBoot    db    ' - writing BOOT$'
  106. WritingFAT    db    ', FATs$'
  107. WritingDIR    db    ', DIR.$'
  108.  
  109. ErrorTbl    db    1,'Invalid command                '
  110.         db    2,'Address mark not found.        '
  111.         db    4,'Requested sector not found.    '
  112.         db    8,'DMA overrun on operation.      '
  113.         db    10h,'Bad CRC on diskette read/write.'
  114.         db    20h,'Controller failure.            '
  115.         db    40h,'SEEK operation failed.         '
  116. EndOfErrTbl    equ    $
  117.  
  118. FatalErr    db    bell,cr,lf,lf,'Door Open, Write-protected disk,'
  119.         db    ' or Drive Fails to respond.'
  120.         db    cr,lf,'Please fix problem and hit Enter to continue,'
  121.         db    'or ESCape to abort...$'
  122.  
  123. BadClusters    db    cr,lf,lf,'Bad sectors :'
  124. BadClNr        db    '       Cluster(s) disabled.',cr,lf,lf,'$'
  125. ;
  126. ErrBadSec    db    bs,bs,', Sec: '
  127. ErrSec        db    ' , Error '
  128. ErrCode        db    '   hex : '
  129. ErrMsg        db    'Unknown error.                 ',cr,lf,'$'
  130. ;
  131. ;
  132. ; Flags, set according to switches
  133. ;
  134. OptionsFlag    db    0    ;default is No Verify, Normal Disk
  135. CtrlBreak    db    0    ;Ctrl-Break flag on entry
  136. ;
  137. ; Disk characteristics, other parms are found in BootSector
  138. ;
  139. DirSecs        dw    7    ;DIRectory size in sectors
  140. DskTrks        db    40    ;Cyls/disk
  141. CurTrk        db    -1    ;Current track
  142. CurDrv        db    0    ;Current drive, binary, BIOS way (A:=0,..)
  143. NeedSetup    db    1    ;nonzero if default parms are in effect
  144.  
  145.     even            ;Align for those w/8086 processors
  146.  
  147. RetryCount    dw    0    ;Count of retries
  148. MaxTries    dw    2    ;Maximum retries attempted
  149. BadSecCnt    dw    0    ;Count of Bad Sectors
  150. NextSec        dw    0    ;Temp storage for next sector #
  151. INT1Eoff    dw    0    ;INT 1Eh offset
  152. INT1Eseg    dw    0    ;INT 1Eh segment
  153. INT24off    dw    0    ;Critical error handler offset
  154. INT24seg    dw    0    ;Critical error segment
  155. ;
  156. HexTbl        db    '0123456789abcdef'
  157. ;
  158. ID_tbl        dw    Side0    ;addr of table of ID's for track 0, side 0
  159.  
  160. Side0        db    0,0,1,2
  161.         db    0,0,2,2
  162.         db    0,0,3,2
  163.         db    0,0,4,2
  164.         db    0,0,5,2
  165.         db    0,0,6,2
  166.         db    0,0,7,2
  167.         db    0,0,8,2
  168.         db    0,0,9,2        ;end of side 0
  169.  
  170.         db    0,1,1,2        ;side 1 now
  171.         db    0,1,2,2
  172.         db    0,1,3,2
  173.         db    0,1,4,2
  174.         db    0,1,5,2
  175.         db    0,1,6,2
  176.         db    0,1,7,2
  177.         db    0,1,8,2
  178.         db    0,1,9,2        ;end of track, side 1
  179.  
  180. SideLen        equ    36
  181. ;
  182. ;
  183. ; Anatomy of our Boot sector
  184. ;
  185. BootSector    equ    $
  186.  
  187.         jmp    BootMsg
  188.  
  189.         db    'SDF  v01'    ;OEM name, 8 chars
  190.         dw    512        ;Sector size
  191.         db    2        ;Cluster size in sectors
  192.         dw    1        ;Reserved sectors
  193.         db    2        ;Number of FATs
  194. DirSize        dw    112        ;Directory entries
  195. TotSecs        dw    720        ;Total sectors
  196. MediaDes    db    0FDh        ;Media descriptor
  197. FatSize        dw    2        ;FAT size in sectors
  198.         dw    9        ;Sectors per Track
  199.         dw    2        ;Number of heads
  200.         dw    0        ;Number of hidden sectors
  201.         db    0        ;filler
  202.         db    0        ;head
  203.         db    10        ;length    of BIOS    file
  204.         db    hsr        ;The DPB, remember ?
  205.         db    2
  206.         db    25h
  207.         db    2
  208.         db    9
  209.         db    42
  210.         db    -1
  211.         db    80
  212.         db    0F6h
  213.         db    hst
  214.         db    1
  215.  
  216. NoBootMsg    equ    $
  217.  
  218.     db    cr,lf,lf
  219.     db    ulc,50 DUP (hb),urc,cr,lf
  220.     db    vb,'   This diskette has been formatted by SDF and    ',vb,cr,lf
  221.     db    vb,'    contains no system to boot from. Either       ',vb,cr,lf
  222.     db    vb,'  remove it and hit a key to boot from hard disk  ',vb,cr,lf
  223.     db    vb,'  if any, or replace it with another disk with a  ',vb,cr,lf
  224.     db    vb,'   system to boot from and hit a key when ready.  ',vb,cr,lf
  225.     db    llc,50 DUP (hb),lrc,cr,lf,lf,0
  226.  
  227.  
  228. BootMsg:
  229.     cli                ;no interrupts
  230.     cld                ;forward direction
  231.     mov    AX,07C0h        ;Boot runtime address
  232.     mov    DS,AX            ;to DS
  233.     mov    ES,AX
  234.     mov    SS,AX
  235.     mov    SP,0            ;temp stack at top of segment 
  236.     mov    SI,(OFFSET NoBootMsg - OFFSET BootSector) ;Msg ptr
  237. BNextChar:
  238.     lodsb                ;Get byte fm msg
  239.     or    AL,AL            ;a null ?
  240.     je    ReBoot            ;yes, print msg done
  241.     mov    AH,0Eh            ;print char, no bells and whistles
  242.     int    10h            ;Bios output char INT
  243.     jmp    SHORT BNextchar        ;loop for all string
  244. ;
  245. ReBoot:    xor    AH,AH            ;wait for key hit
  246.     int    16h
  247.  
  248.     int    19h            ;and try booting again 
  249.  
  250.  
  251. BEndOfStuff    equ    $
  252.  
  253.     db    (510 - (BEndOfStuff - BootSector)) DUP (0)    ;filler
  254.  
  255.     db    55h,0AAh        ;DOS disk signature
  256. ;
  257. ; End of boot sector
  258. ;
  259. ; First sector of File Allocation Table
  260. ;
  261. FatSec1    equ    $
  262.     db    0FDh            ;FAT - Media descriptor
  263.     db    0FFh
  264.     db    0FFh
  265.     db    509 DUP (0)        ;to get a full sector
  266.  
  267. FatSec2    db    512 DUP (0)        ;FAT, second sector
  268.     db    512 DUP (0)        ;FAT, third sector
  269. ;
  270. DirSec1    equ    $
  271. DskLbl    db    'SDF--------'        ;Dir entry for disk label, 11 char
  272.     db    28h            ;Attributes : Label + Archive
  273.     db    10 DUP (0)
  274. TimeLo    db    0
  275. TimeHi    db    0
  276. Date    dw    0
  277.     db    486 DUP (0)        ;full sector
  278. ;
  279. DirSec2    db    512 DUP (0)        ;2nd and other sectors
  280. ;
  281. ;
  282. ; Control-Break handler : DO NOT give user a chance to exit w/^C or Break
  283. ; without resetting the environement...
  284. ;
  285. ControlBreak: 
  286.  
  287.     iret                ;trap ^C and simply return
  288. ;
  289. ;
  290. ; Critical Error handler:  Same as above.  Note that, contrary to documentation
  291. ; (under DOS 2.1 at least), selecting 'a' under Abort/Retry/Fail does not put
  292. ; you into INT 23.
  293. ;
  294. CritError:
  295.     push    AX
  296.     push    DX
  297.     push    DS
  298.     push    CS
  299.     pop    DS
  300.     call    Restore
  301.     pop    DS
  302.     pop    DX
  303.     pop    AX
  304.     jmp    far cs:[INT24off]    ;go to the previous handler
  305. ;
  306. ; Let's go to it now
  307. ;
  308. GetCmdLine:
  309.  
  310.     mov    DX,offset Welcome    ;print welcome msg
  311.     call    PrintString
  312.     mov    SI,80H            ;Peek at input bfr char count
  313.     lodsb                ;get byte
  314.     cbw                ;make word
  315.     or    AX,AX            ;any option ?
  316.     jne    GCL1            ;yes
  317. Usage:    mov    DX,offset UsageMessage
  318.     call    PrintString        ;Print and fall thru ErrorExit
  319. ;
  320. ; Error Exit, w/ return code 1, Normal Exit, w/ return code 0
  321. ;
  322. ErrorExit:
  323.     mov    AL,1
  324.     jmp    SHORT    DoExit
  325. ;
  326. Abort:    call    Restore            ;Restore INT 1E, INT 35
  327. ;
  328. Exit:    mov    AL,0            ;normal exit, no error
  329. DoExit:    mov    AH,4Ch            ;Program Exit
  330.     int    21h
  331. ;
  332. ;
  333. ; Carry on parsing command line
  334. ;
  335. GCL1:    mov    CX,AX            ;got something in cmd line, count to CX
  336.     call    ParseSwitches        ;Parse cmd line "/" switches
  337.     mov    SI,81h            ;Get drive spec
  338. GCL2:    lodsb
  339.     cmp    AL,' '            ;skip spaces
  340.     loopz    GCL2
  341.     jcxz    Usage            ;Nuts, give Usage Msg
  342.     cmp    AL,cr
  343.     jz    Usage
  344.     and    AL,5fh            ;Make drive letter uppercase
  345.     mov    Drive,AL        ;Put drive letter in msg
  346.     sub    AL,'A'            ;make binary, BIOS way
  347.     mov    CurDrv,AL        ;Store in current drive
  348.     cmp    AL,1            ;Drive MUST be 0 or 1
  349.     jg    BadDrive
  350.     lodsb
  351.     cmp    AL,':'            ;Make sure this WAS a drive spec
  352.     jne    BadDrive        ;no, it was not
  353.     jmp    Setup            ;Yes, indeed
  354. BadDrive:
  355.     mov    DX,OFFSET DriveMissing
  356.     call    PrintString
  357.     jmp    Usage
  358. ;
  359. ;
  360. A$Ret:    ret
  361. ;
  362. ; Parse command line switches
  363. ;
  364. ParseSwitches:
  365.     mov    DI,81h            ;peek at cmd line
  366. PS1:    mov    AL,'/'
  367.     repne    scasb            ;search for "/", length in CX
  368.     jne    A$Ret            
  369.     jcxz    A$Ret            ;none, or no more
  370.     mov    BYTE PTR [DI-1],cr    ;Got a "/", put a CR for later use
  371.     cmp    BYTE PTR [DI-2],' '    ;Previous char was space ?
  372.     jne    PS2            ;no
  373.     mov    BYTE PTR [DI-2],cr    ;yes, force to CR
  374. PS2:    mov    SI,DI
  375.     lodsb                ;get switch
  376.     and    AL,5Fh            ;Force uppercase
  377. PS3:    cmp    AL,'V'            ;/Verify ?
  378.     jne    PS4            ;no
  379.     mov    OptionsFlag,1        ;yes, remember that
  380.     mov    WORD PTR DskLbl+6,'V+'    ;put in disk label
  381.     mov    BYTE PTR DiskType+10,'$' ;truncate "Without" msg
  382.     jmp    PS1            ;parse next
  383. PS4:    cmp    AL,'Q'            ;/Quad density ?
  384.     jne    PS5            ;no, unknown switch
  385.     mov    BYTE PTR DiskType+2,'Q'    ;Flag, and Description
  386.     mov    DskTrks,80        ;80 tracks
  387.     mov    FatSize,3        ;FAT is 3 sectors long
  388.     mov    TotSecs,1440        ;1440 sectors
  389.     mov    MediaDes,0F9h        ;to Boot Sector
  390.     mov    WORD PTR DskLbl+8,'Q+'    ;put in disk label
  391.     jmp    PS1            ;parse next switch
  392. PS5:    mov    DX,OFFSET WrongSwitch
  393.     call    PrintString
  394.     jmp    Usage    
  395.  
  396. ;
  397. ; Restore : Restore the world as it was on entry
  398. ;
  399. Restore:cmp    NeedSetup,0        ;see if we need to do this
  400.     jnz    Res1            ;if not
  401.     mov    NeedSetup,1
  402.  
  403.     lds    DX,DWORD PTR INT1Eoff    ;previous INT 1Eh vector
  404.     mov    AX,251Eh        ;restore it
  405.     int    21h
  406.     push    CS            ;restore DS
  407.     pop    DS
  408.  
  409.     mov    AH,0            ;Reset Disk System
  410.     int    13h
  411.  
  412.     mov    AX,3301h        ;set Ctrl-Break flag
  413.     mov    DL,CtrlBreak        ;restore as was on entry
  414.     int    21h
  415.  
  416. Res1:    ret
  417. ;
  418. ;
  419. ; Setup : Set up the world
  420. ;
  421. Setup:    mov    AH,AL            ;colon to AH
  422.     mov    AL,CurDrv
  423.     add    AL,'A'
  424.     mov    WORD PTR DskLbl+4,AX    ;put DriveSpec in disk label
  425.  
  426.     mov    AX,3300h        ;Get CtrlBreak flag
  427.     int    21h
  428.     mov    CtrlBreak,DL        ;save flag
  429.  
  430.     mov    DX,OFFSET ControlBreak    ;our handler
  431.     mov    AX,2523h        ;Set Interrupt Vector 23h
  432.     int    21h
  433.  
  434.     mov    AX,3524h        ;get Interrupt Vector 24h
  435.     int    21h
  436.     mov    INT24off,BX
  437.     mov    INT24seg,ES
  438.     mov    DX,OFFSET CritError    ;our handler
  439.     mov    AX,2524h        ;Set Interrupt Vector 24h
  440.     int    21h
  441.  
  442.     mov    AX,351Eh        ;get Interrupt Vector 1Eh
  443.     int    21h
  444.     mov    INT1Eoff,BX
  445.     mov    INT1Eseg,ES
  446.  
  447.     push    CS
  448.     pop    ES
  449.                     ;fall thru format loop
  450. ;
  451. Do_It:    mov    DX,OFFSET InsertDisk    ;say "Insert diskette in drive.."
  452.     call    PrintString
  453. ;
  454. GetChar:mov    AH,0            ;get char function
  455.     int    16h
  456.     cmp    AL,escape
  457.     jne    GC1
  458.     jmp    Abort
  459. GC1:    cmp    AL,cr
  460.     jne    GetChar            ;Escape or CR only !
  461.  
  462.     cmp    NeedSetup,0        ;see if we need to do this
  463.     je    GC2            ;if not
  464.     mov    NeedSetup,0
  465.  
  466.     mov    DX,OFFSET OurDBP    ;our DBP
  467.     mov    AX,251Eh        ;Set Interrupt Vector 1Eh
  468.     int    21h
  469.  
  470.     mov    AH,0            ;Reset Disk System
  471.     int    13h            ;our DBP is now in effect
  472.  
  473.     mov    AX,3301h        ;set flag
  474.     xor    DL,DL            ;set checking OFF
  475.     int    21h
  476.  
  477. GC2:    mov    DX,OFFSET Formatting    ;"Formatting..."
  478.     call    PrintString
  479.     mov    DX,OFFSET Verify
  480.     call    PrintString
  481.     mov    BadSecCnt,0        ;no bad sector so far
  482.     call    PrepareFat
  483. ;
  484. ; Format all disk now
  485. ;
  486.     call    DoFormat        ;Here we go
  487.     mov    AX,BadSecCnt        ;any bad sector ?
  488.     or    AX,AX
  489.     je    NoBadSec        ;no
  490.     mov    SI,OFFSET BadClNr    ;Pointer to decimal places
  491.     call    AX2dec            ;convert to decimal
  492.     mov    DX,OFFSET BadClusters    ;Bad Clusters msg
  493.     call    PrintString    
  494. ;
  495. ; Write Boot, FAT, DIR
  496. ;
  497. NoBadSec:call    WriteBFD        ;write Boot, Fat, Dir
  498. ;
  499. ; Show available space
  500. ;
  501.     mov    AH,0Dh            ;reset disk system
  502.     int    21h
  503.     mov    AH,36h            ;get free space
  504.     mov    DL,CurDrv        ;for our drive
  505.     inc    DL            ;DOS way
  506.     int    21h
  507.     mov    AX,BX            ;clusters to AX
  508.     mov    SI,OFFSET Clusters
  509.     call    AX2dec            ;convert and fall thru print
  510. ;
  511. ; Done - prompt for another disk to format
  512. ;
  513.     mov    DX,OFFSET Again        ;"Hit enter to format another..."
  514.     call    PrintString
  515.     call    MotorOff        ;Turn motor off
  516.     call    Whistle            ;Wake him up
  517.     jmp    GetChar            ;get char
  518.  
  519.  
  520. ;
  521. ; Prepare first FAT sector - This stuff required for multiple formatting
  522. ;
  523. PrepareFat:
  524.     sub    AX,AX            ;clear FAT to all zeros
  525.     mov    DX,FatSize        ;How many sectors ?
  526.     mov    DI,OFFSET FatSec1
  527. PF1:    mov    CX,512/2        ;sector size, in words
  528.     repz    stosw            ;for speed
  529.     dec    DX            ;next FAT
  530.     jnz    PF1
  531.     mov    AL,MediaDes        ;get Media Descriptor from Boot Sec
  532.     mov    BYTE PTR FatSec1,AL        ;move in place
  533.     mov    WORD PTR FatSec1+1,0FFFFh
  534.     ret
  535.  
  536. ;
  537. ; Here to REALLY format a disk
  538. ;
  539. DoFormat:
  540.     mov    CurTrk,-1        ;Initialize track nr
  541. NextTrk:                ;Prepare table for Track/sect. ID's
  542.     inc    CurTrk            ;Next track
  543.     mov    CH,CurTrk        ;to CH
  544.     cmp    CH,DskTrks        ;All done ?
  545.     jb    NT1            ;not yet
  546.     ret                ;yes, return
  547. NT1:    mov    DI,ID_tbl        ;Point to table
  548.     mov    AL,18            ;18 sectors per Cyl
  549. NT2:    mov    [DI],CH            ;move Track # in table
  550.     add    DI,4            ;point to next entry
  551.     dec    AL            ;all done ?
  552.     jnz    NT2            ;No, loop
  553.     mov    AH,1            ;Give user a chance to abort
  554.     int    16h            ;Keyboard hit ?
  555.     jz    NT3            ;no
  556.     cmp    AL,escape        ;yes, Escape to abort ?
  557.     jne    NT3
  558.     jmp    Abort
  559. ;
  560. NT3:    mov    AX,0509h        ;Format Track, 9 sectors/trk
  561.     mov    BX,ID_tbl        ;track id table address, side 0
  562.     mov    DL,CurDrv        ;current drive
  563.     mov    DH,0            ;Side 0
  564.     mov    CL,1            ;First sec is #1
  565.     call    PrintProgress        ;Print progress (Track#, Side #)
  566.     int    13h            ;Format track, side 0
  567.     jnc    NT3V            ;No Carry, no error
  568.     call    Retry            ;Carry set, Shall we retry ?
  569.     jnc    NT3            ;yes, if we come here w/Carry clear
  570.                     ;else, give up
  571. NT3V:    test    OptionsFlag,1        ;Should we verify ?
  572.     jz    NT4            ;No, next side
  573. ;
  574. NT3R:    mov    AX,0409h        ;Verify, 9 sectors per track
  575.     int    13h
  576.     jnc    NT4            ;No carry, no error
  577.     call    Retry            ;Carry set, retry ?
  578.     jnc    NT3R            ;Yes, if Carry clear, else give up
  579. NT4:    mov    DH,1            ;Side 1
  580.     mov    AX,0509h        ;Format Track, 9 sectors/trk
  581.     mov    BX,ID_tbl        ;track id table address, side 1
  582.     add    BX,SideLen
  583.     mov    DL,CurDrv        ;current drive
  584.     mov    CL,1            ;First sec is #1
  585.     call    PrintProgress        ;Print progress (Track#, Side #)
  586.     int    13h            ;Format track, side 1
  587.     jnc    NT4V            ;no error
  588.     call    Retry            ;Carry set, error
  589.     jnc    NT4            ;Retry if Carry clear, else give up
  590. NT4V:    test    OptionsFlag,1        ;Should we verify ?
  591.     jz    NextTrk            ;no, next track
  592. ;
  593. NT4R:    mov    AX,0409h        ;Verify, 9 sectors per track
  594.     int    13h
  595.     jc    NT5            ;error !
  596.     jmp    NextTrk            ;no error, next track
  597. NT5:    call    Retry            ;Carry set, retry ?
  598.     jnc    NT4R            ;yes
  599.     jmp    NextTrk            ;no, next track
  600. ;
  601. Retry:    cmp    AH,3            ;Door open/Write protected ?
  602.     je    R1            ;yes
  603.     cmp    AH,80h            ;Attachment failed to respond ?
  604.     jne    R2            ;no, other error
  605. R1:    mov    DX,OFFSET FatalErr    ;tell him he'd better close the door
  606.     call    PrintString        ;..or remove the write-protect tab
  607.     pop    AX            ;clean up stack, we won't return
  608.     pop    AX            ;two calls to clean up
  609.     jmp    GetChar            ;OK, we may restart now
  610. R2:    cmp    AH,9            ;DMA boundary error?
  611.     jne    R4            ;no, other error
  612.     push    CX            ;save registers
  613.     push    SI
  614.     mov    DI,ES            ;compute offset of next DMA page
  615.     neg    DI
  616.     mov    CL,4
  617.     shl    DI,CL
  618.     cmp    DI,EndCode
  619.     ja    R3            ;if it's not in the code segment
  620.     mov    DI,EndCode        ;don't clobber code
  621. R3:    mov    SI,ID_tbl        ;move the table pointer
  622.     mov    ID_tbl,DI
  623.     mov    CX,SideLen        ;move the table itself
  624.     rep    movsw
  625.     cmp    SI,DI
  626.     pop    SI            ;restore registers
  627.     pop    CX
  628.     je    R4            ;if this should already be fixed
  629.     clc
  630.     ret
  631. R4:    push    DX
  632.     mov    DX,OFFSET ShowRetry    ;Show 'R' to indicate a retry
  633.     call    PrintString
  634.     pop    DX
  635.     inc    RetryCount
  636.     mov    DI,MaxTries        ;limit exceeded ?
  637.     cmp    RetryCount,DI
  638.     ja    SecIsBad        ;Yes, this one is really bad
  639.     mov    AH,0            ;No, Reset Disk System
  640.     int    13h
  641.     clc                ;clear carry
  642.     ret                ;and return to try again
  643. ;
  644. ; If we come here, we really have to deal with a bad sector
  645. ;
  646. SecIsBad: call    ShowBadSec
  647.     inc    BadSecCnt        ;count it
  648.     call    MarkBad            ;Mark whole cluster
  649.     mov    RetryCount,0        ;Reset retry count
  650.     stc                ;Set Carry to indicate "give up"
  651.     ret                ;go process next side or track
  652. ;
  653. ;
  654. ; Mark a bad sector (cluster) in FAT
  655. ;
  656. MarkBad:push    AX
  657.     push    BX
  658.     push    CX
  659.     push    DX
  660.     push    DI
  661.     push    SI
  662.     push    DS            ;We have to fetch..
  663.     mov    AX,40h            ;.. the faulty sector
  664.     mov    DS,AX            ;.. in the BIOS area
  665.     mov    BX,47h
  666.     mov    CL,BYTE PTR [BX]    ;Get sector number
  667.     pop    DS
  668.     mov    AL,CH            ;Track # to AL; AH is already 0
  669.     xor    CH,CH
  670.     cmp    DH,0            ;Side 0 ?
  671.     je    MB1
  672.     add    CL,9            ;Side 1, add 9 sects for side 0
  673. MB1:    shl    AX,1            ;* 2 heads
  674.     mov    BX,9            ;* 9 sectors per track
  675.     mul    BX            ;compute absolute sector #
  676.     add    AX,CX
  677.     sub    AX,FatSize        ;minus 1st FAT size
  678.     sub    AX,FatSize        ;minus 2nd FAT size
  679.     sub    AX,DirSecs        ;minus Directory size
  680.     mov    BL,2            ;disk heads
  681.     div    BX
  682.     add    AX,1
  683.     mov    CX,3
  684.     mul    CX
  685.     shr    AX,1            ; / 2
  686.     mov    DI,AX
  687.     lea    SI,[DI+FatSec1]        ;pointer into FAT
  688.     mov    DI,SI
  689.     lodsw                ;get cluster entry
  690.     mov    DX,0FF70h        ;12 bits, left aligned
  691.     jb    MB2            ;if even
  692.     mov    DX,0FF7h        ;if odd
  693. MB2:    or    AX,DX            ;merge w/ word to mark bad
  694.     stosw                ;store back in FAT
  695.     pop    SI
  696.     pop    DI
  697.     pop    DX
  698.     pop    CX
  699.     pop    BX
  700.     pop    AX
  701.     ret
  702. ;
  703. ; Write Boot sector, then FATs, then DIR.
  704. ;
  705. WriteBFD:
  706.     mov    DX,OFFSET WritingBoot
  707.     call    PrintString
  708.     mov    AL,CurDrv
  709.     lea    BX,BootSector        ;boot sector
  710.     mov    CX,1            ;1 sector to write
  711.     mov    DX,0            ;absolute sector 0
  712.     call    AbsSecWrite
  713. ;
  714. ; Write FAT(s)
  715. ;
  716.     push    DX            ;Preserve Sector Nr
  717.     mov    DX,OFFSET WritingFAT    ;"FATs"
  718.     call    PrintString
  719.     pop    DX
  720.     mov    AL,CurDrv        ;current drive
  721.     lea    BX,FatSec1        ;point to FAT 1st sector
  722.     mov    CX,1            ;1 sector write
  723.     inc    DX            ;DX knows which
  724.     call    AbsSecWrite
  725.     mov    CX,FatSize        ;sectors/FAT
  726.     dec    CX            ;One written already
  727.     lea    BX,FatSec2        ;get FAT 2nd sector
  728.     mov    AL,CurDrv        ;current drive
  729.     inc    DX            ;next sector(s)
  730.     call    AbsSecWrite
  731.     add    DX,CX            ;count sectors written this time
  732. ;
  733. ; Write second FAT
  734. ;
  735.     mov    AL,CurDrv        ;current drive
  736.     mov    BX,OFFSET FatSec1    ;FAT
  737.     mov    CX,1            ;1 sector, DX knows which
  738.     call    AbsSecWrite
  739.     mov    CX,FatSize        ;How many remaining ?
  740.     dec    CX            ;One already written
  741.     mov    BX,OFFSET FatSec2    ;point to FAT 2nd sector
  742.     mov    AL,CurDrv        ;current drive
  743.     inc    DX            ;next FAT sector(s)
  744.     call    AbsSecWrite
  745.     add    DX,CX
  746.     mov    NextSec,DX        ;remember next sector to write
  747. ;
  748. ; Write Directory
  749. ;
  750.     mov    DX,OFFSET WritingDIR    ;"DIRectory"
  751.     call    PrintString
  752. ;
  753. ; Update Disk Label Date and Time
  754. ;
  755.     mov    AH,2Ch            ;Get Time
  756.     int    21h
  757.     mov    BX,CX            ;Minutes, Seconds
  758.     mov    AX,CX
  759.     mov    CL,3
  760.     shl    CH,CL            ;Shift to move hour in place
  761.     shr    BL,CL            ;Shift to keep high 3 bits of min
  762.     add    CH,BL            ;merge
  763.     mov    TimeHi,CH        ;move in place
  764.     and    AL,7            ;keep min. lower 3 bits
  765.     shl    AL,1            ;shift
  766.     mov    CL,5
  767.     shr    DX,CL            ;Shift seconds
  768.     add    DH,AL            ;merge
  769.     mov    TimeLo,DH        ;move in place
  770.     mov    AH,2Ah            ;Get Date
  771.     int    21h
  772.     sub    CX,1980            ;From 1980 on
  773.     shl    CL,1
  774.     mov    BX,DX
  775.     mov    AH,CL
  776.     mov    CL,3
  777.     shr    DH,CL
  778.     add    AH,DH
  779.     mov    CL,5
  780.     shl    BH,CL
  781.     add    BH,DL
  782.     mov    AL,BH
  783.     mov    Date,AX            ;Move date in place
  784.     mov    AL,CurDrv        ;current drive
  785.     mov    BX,OFFSET DirSec1    ;First sector of DIR
  786.     mov    DX,NextSec        ;current sector
  787.     mov    CX,1            ;1 sector to write
  788.     call    AbsSecWrite
  789.     mov    AL,CurDrv
  790.     mov    BX,OFFSET DirSec2
  791.     mov    CX,DirSecs        ;How many sectors
  792.     dec    CX            ;One already written
  793. WD1:    push    CX
  794.     mov    CX,1            ;1 sector write
  795.     inc    DX            ;next one
  796.     call    AbsSecWrite
  797.     pop    CX            ;how many remaining ?
  798.     loop    WD1
  799.     ret                ;Done, next disk please.
  800. ;
  801. ; Print progress : Track nn Side n - inline decimal conversion
  802. ;
  803. PrintProgress:
  804.     push    AX
  805.     push    DX
  806.     mov    AL,DH            ;Side #
  807.     add    AL,'0'            ;Brute force ascify
  808.     mov    SideNr,al        ;Put side # in msg
  809.     mov    AL,CH            ;get track #
  810.     aam                ;THE trick
  811.     xchg    AL,AH            ;swap
  812.     add    AX,'00'            ;Ascify
  813.     mov    WORD PTR TrackNr,AX    ;Put track # in msg
  814.     mov    DX,OFFSET Track        ;say "Track..., Side..."
  815.     call    PrintString
  816.     pop    DX
  817.     pop    AX
  818.     ret
  819. ;
  820. ; Here to show that we have a bad sector
  821. ;
  822. ShowBadSec:
  823.     push    AX
  824.     push    BX
  825.     push    CX
  826.     push    DX
  827.     push    DI
  828.     push    SI
  829.     mov    DX,AX            ;Save AX for further hex printing
  830.     sub    BX,BX
  831.     mov    BL,AH            ;remember error code
  832.     mov    DI,OFFSET ErrorTbl    ;Table for INT 13 error codes & msgs
  833.     mov    AL,AH            ;Error code to AL
  834.     MOV    CX,OFFSET EndOfErrTbl
  835.     sub    CX,DI            ;compute table length
  836.     repnz    scasb            ;search for error code
  837.     jnz    SBS1            ;Not found, "Unknown Error"
  838.     mov    SI,DI            ;Got it, Ptr to SI
  839.     mov    CX,31            ;err msg length
  840.     mov    DI,OFFSET ErrMsg    ;Point to destination
  841.     repz    movsb            ;Move Err Msg in place
  842. SBS1:    mov    AL,DH            ;Get AH : error code
  843.     call    AL2hex            ;Convert
  844.     mov    WORD PTR ErrCode,AX    ;move AH (hex) in msg
  845.     push    DS
  846.     mov    AX,40h            ;Point to BIOS data area
  847.     mov    DS,AX
  848.     mov    BX,47h            ;the right place in BIOS area
  849.     mov    AL,BYTE PTR [BX]    ;BIOS knows which sector causes problem
  850.     pop    DS
  851.     add    AL,'0'            ;ascify
  852.     mov    ErrSec,AL        ;move sec # in msg
  853.     mov    DX,OFFSET ErrBadSec    ;give error msg
  854.     call    PrintString
  855.     pop    SI
  856.     pop    DI
  857.     pop    DX
  858.     pop    CX
  859.     pop    BX
  860.     pop    AX
  861.     ret
  862. ;
  863. ;
  864. ; AL2hex : binary AL to 2 hex digits in AX conversion
  865. ;
  866. AL2hex:    push    BX
  867.     push    CX
  868.     push    DX
  869.     push    SI
  870.     mov    BL,AL            ;will use BX as offset to tbl
  871.     mov    CL,4            ;bits to shift
  872.     sub    BH,BH
  873.     shr    BL,CL
  874.     and    AL,0Fh            ;mask off bits
  875.     sub    AH,AH
  876.     mov    SI,OFFSET HexTbl    ;point to hex tbl
  877.     add    SI,BX
  878.     mov    DL,[BX+HexTbl]
  879.     mov    BX,AX
  880.     mov    DH,[BX+HexTbl]
  881.     mov    AX,DX
  882.     pop    SI
  883.     pop    DX
  884.     pop    CX
  885.     pop    BX
  886.     ret
  887. ;
  888. ;
  889. ; AX2dec : routine to convert AX to decimal string at DS:SI
  890. ;
  891. AX2dec:    push    AX
  892.     push    CX
  893.     push    SI
  894.     xor    CL,CL            ;clear 10000 counter
  895. s10000:    inc    CL
  896.     sub    AX,10000
  897.     jnc    s10000
  898.     add    AX,10000        ;one SUB too much
  899.     add    CL,'0'-1        ;adjust and ascify
  900.     mov    [SI],CL            ;store in string
  901.     inc    SI
  902.     xor    CL,CL            ;clear 1000 counter
  903. s1000:    inc    CL
  904.     sub    AX,1000
  905.     jnc    s1000
  906.     add    AX,1000            ;one SUB too much
  907.     add    CL,'0'-1        ;adjust and ascify
  908.     mov    [SI],CL            ;store in string
  909.     inc    SI
  910.     xor    CL,CL            ;clear 100 counter
  911. s100:    inc    CL
  912.     sub    AX,100
  913.     jnc    s100
  914.     add    AX,100            ;one SUB too much
  915.     add    CL,'0'-1        ;adjust and ascify
  916.     mov    [SI],CL            ;store in string
  917.     inc    SI
  918.     aam                ;Convert value <100
  919.     xchg    AL,AH            ;swap
  920.     add    AX,'00'            ;Ascify
  921.     mov    [SI],AX
  922.     pop    SI            ;restore string ptr
  923.     mov    CX,5            ; 5 bytes to search
  924. AX2D1:    cmp    BYTE PTR [SI],'0'    ;leading Zero ?
  925.     jne    AX2D2            ;no or no more
  926.     mov    BYTE PTR [SI],' '    ;yes, make leading space
  927.     inc    SI
  928.     loop    AX2D1            ;loop for all
  929. AX2D2:    pop    CX
  930.     pop    AX
  931.     ret
  932. ;
  933. ;
  934. ; PrintString : print string pointed by DX, terminated by '$'
  935. ;
  936. PrintString:
  937.  
  938.     push    ax
  939.     mov    ah,9
  940.     int    21h
  941.     pop    ax
  942.     ret
  943. ;
  944. ; Absolute sector Write
  945. ;
  946. AbsSecWrite:
  947.  
  948.     push    AX
  949.     push    BX
  950.     push    CX
  951.     push    DX
  952.     int    26h            ;absolute sector write
  953.     jnb    ASW1            ;no carry, no error
  954.     xchg    CX,DX
  955.     mov    DH,DL
  956.     call    ShowBadSec
  957. ASW1:    popf
  958.     pop    DX
  959.     pop    CX
  960.     pop    BX
  961.     pop    AX
  962.     ret
  963. ;
  964. ; MotorOff - Turn drive motor off
  965. ;
  966. motor_count    equ    440h
  967. ;
  968. MotorOff:
  969.     push    ds
  970.     xor    ax,ax
  971.     mov    ds,ax
  972.     mov    byte [motor_count],1    ;turn off drive motor next timer tick
  973.     pop    ds
  974.     ret
  975. ;
  976. ; Whistle - Wolf's whistle
  977. ;
  978. i8253    equ    40h        ;Timer chip base address
  979. i8255    equ    60h        ;PPI chip base address
  980. ;
  981. Whistle:
  982.     push    AX
  983.     mov    AL,0B6h        ;Counter 2, 2 bytes count, mode 3
  984.     out    (i8253+3),AL    ;Write Mode Word
  985.     mov    AX,1000        ;Divisor
  986.     push    AX
  987.     out    (i8253+2),AL    ;load lo byte
  988.     xchg    AH,AL
  989.     out    (i8253+2),AL    ;load hi byte
  990.     in    AL,(i8255+1)    ;8255, port B
  991.     or    AL,3        ;turn on bottom two bits, spkr on
  992.     out    (i8255+1),AL
  993.     pop    AX
  994. W1:    call    SwLoop        ;soft timing loop
  995.     dec    AX
  996.     out    (i8253+2),AL    ;load lo byte
  997.     xchg    AH,AL
  998.     out    (i8253+2),AL    ;load hi byte
  999.     xchg    AH,AL
  1000.     jne    W1        ;loop
  1001.     in    AL,(i8255+1)    ;8255, port B
  1002.     and    AL,NOT 3    ;turn off bottom two bits, spkr off
  1003.     out    (i8255+1),AL
  1004.     pop    AX
  1005.     ret
  1006. ;
  1007. ; Soft loop for Whistle
  1008. ;
  1009. SwLoop:    push    CX
  1010.     mov    CX,100
  1011. SWL:    loop    SWL
  1012.     pop    CX
  1013.     ret
  1014. ;
  1015. ; End of code
  1016. ;
  1017. EndCode:
  1018. ;
  1019.     SDF    ends
  1020. ;
  1021. end    start
  1022.